package log

import (
	"fmt"
	"gitee.com/Hu-Lyndon/distill-resk/infra"
	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
	"github.com/rifflock/lfshook"
	log "github.com/sirupsen/logrus"
	"github.com/tietang/go-utils"
	"github.com/tietang/props/kvs"
	prefixed "github.com/x-cray/logrus-prefixed-formatter"
	"io"
	"os"
	"path"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

var formatter *prefixed.TextFormatter
var lfh *utils.LineNumLogrusHook

func init() {
	// 定义日志格式
	// formatter := &log.TextFormatter{} // 这里是原生的日志格式化
	formatter = &prefixed.TextFormatter{} // 这个是第三方的插件
	formatter.FullTimestamp = true
	formatter.TimestampFormat = "2006-01-02T15:04:05.000000"
	// 控制台高亮显示
	formatter.ForceColors = true
	formatter.DisableColors = false
	formatter.ForceFormatting = true // 强制格式化
	formatter.SetColorScheme(&prefixed.ColorScheme{
		InfoLevelStyle:  "green",
		WarnLevelStyle:  "yellow",
		ErrorLevelStyle: "red",
		FatalLevelStyle: "red",
		PanicLevelStyle: "red",
		DebugLevelStyle: "gray",
		PrefixStyle:     "cyan",
		TimestampStyle:  "37", //"black+h",
	})
	log.SetFormatter(formatter)
	// 日志级别
	level := os.Getenv("log.debug")
	if level == "true" {
		log.SetLevel(log.DebugLevel)
	}

	//开启调用函数、文件、代码行信息的输出
	log.SetReportCaller(true)
	//设置函数、文件、代码行信息的输出的hook
	SetLineNumLogrusHook()

	// 日志文件输出和滚动
	/*dummyTime := time.Now().Add(-7 * 24 * time.Hour)
	  dummyTime = dummyTime.Add(time.Duration(-1 * dummyTime.Nanosecond()))
	  clock := clockwork.NewFakeClockAt(dummyTime)*/
	//rotateWriter, err := rotatelogs.New(`D:\iProject\go-workerspace\src\lyndon.com\iGoLearn\resk\logs\log%Y%m%d%H%M%S`,
	//    rotatelogs.WithClock(rotatelogs.Local),             // 设置时区
	//    rotatelogs.WithMaxAge(time.Duration(0)), // 文件保留时间，设置为0或小于0时，默认为7天
	//    rotatelogs.WithRotationCount(0),         // 保留文件的数量
	//)
	//
	//if err != nil {
	//    panic(err)
	//}
	//
	//log.AddHook(lfshook.NewHook(
	//    lfshook.WriterMap{
	//        log.InfoLevel:  rotateWriter,
	//        log.ErrorLevel: rotateWriter,
	//    },
	//    formatter,
	//))

	//log.SetOutput(logf)

	// 日志文件和滚动配置
	//log.Info("测试")
	//log.Debug("测试")

}

func SetLineNumLogrusHook() {
	lfh = utils.NewLineNumLogrusHook()
	lfh.EnableFileNameLog = true
	lfh.EnableFuncNameLog = true
	log.AddHook(lfh)
}

//将滚动日志writer共享给iris glog output
var log_writer io.Writer

//初始化log配置，配置logrus日志文件滚动生成和
func InitLog(conf kvs.ConfigSource) {
	//设置日志输出级别
	level, err := log.ParseLevel(conf.GetDefault("log.level", "info"))
	if err != nil {
		level = log.InfoLevel
	}
	log.SetLevel(level)
	if conf.GetBoolDefault("log.enableLineLog", true) {
		lfh.EnableFileNameLog = true
		lfh.EnableFuncNameLog = true
	} else {
		lfh.EnableFileNameLog = false
		lfh.EnableFuncNameLog = false
	}

	//配置日志输出目录
	logDir := conf.GetDefault("log.dir", "./logs")
	logTestDir, err := conf.Get("log.test.dir")
	if err == nil {
		logDir = logTestDir
	}
	logPath := logDir //+ "/logs"
	logFilePath, _ := filepath.Abs(logPath)
	log.Infof("log dir: %s", logFilePath)
	logFileName := conf.GetDefault("log.file.name", "red-envelop")
	maxAge := conf.GetDurationDefault("log.max.age", time.Hour*24)
	rotationTime := conf.GetDurationDefault("log.rotation.time", time.Hour*1)
	os.MkdirAll(logPath, os.ModePerm)

	baseLogPath := path.Join(logPath, logFileName)
	//设置滚动日志输出writer
	writer, err := rotatelogs.New(
		strings.TrimSuffix(baseLogPath, ".log")+".%Y%m%d%H.log",
		rotatelogs.WithLinkName(baseLogPath),      // 生成软链，指向最新日志文件
		rotatelogs.WithMaxAge(maxAge),             // 文件最大保存时间
		rotatelogs.WithRotationTime(rotationTime), // 日志切割时间间隔
	)
	if err != nil {
		log.Errorf("config local file system logger error. %+v", err)
	}
	//设置日志文件输出的日志格式
	formatter := &log.TextFormatter{}
	formatter.CallerPrettyfier = func(frame *runtime.Frame) (function string, file string) {
		function = frame.Function
		dir, filename := path.Split(frame.File)
		f := path.Base(dir)
		return function, fmt.Sprintf("%s/%s:%d", f, filename, frame.Line)
	}
	lfHook := lfshook.NewHook(lfshook.WriterMap{
		log.DebugLevel: writer, // 为不同级别设置不同的输出目的
		log.InfoLevel:  writer,
		log.WarnLevel:  writer,
		log.ErrorLevel: writer,
		log.FatalLevel: writer,
		log.PanicLevel: writer,
	}, formatter)

	log.AddHook(lfHook)
	//
	log_writer = writer

}

type LoggerStarter struct {
	infra.BaseStarter
}

func (l *LoggerStarter) Setup(ctx infra.StarterContext) {
	InitLog(ctx.Props())
	log.Info("测试")
	log.Debug("测试debug")
}
